package io.gitee.cdw.sensitive.serializer;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import io.gitee.cdw.sensitive.model.SensitiveSerializerConfig;
import io.gitee.cdw.sensitive.strategy.StrategyManager;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * Jackson数据脱敏BeanSerializerModifier
 *
 * @author Created by chendw on 2023/5/9 9:33.
 */
@Slf4j
public class JacksonSensitiveBeanSerializerModifier extends BeanSerializerModifier {

    private final StrategyManager strategyManager;
    private final SensitiveSerializer serializer;

    public JacksonSensitiveBeanSerializerModifier(StrategyManager strategyManager, SensitiveSerializer serializer) {
        this.strategyManager = strategyManager;
        this.serializer = serializer;
        List<ObjectMapper> mapper = strategyManager.getMapper();
        if (mapper != null) {
            for (ObjectMapper objectMapper : mapper) {
                objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(this));
            }
        }
    }

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        //替换内部的方法
        for (BeanPropertyWriter beanPropertyWriter : beanProperties) {
            if (isStringType(beanPropertyWriter)) {
                String field = beanPropertyWriter.getMember().getDeclaringClass().getName() + "#" + beanPropertyWriter.getName();
                if (strategyManager.contains(field)) {
                    SensitiveSerializerConfig sensitiveSerializerConfig = strategyManager.getSensitiveSerializerConfig(field);
                    log.debug("sensitive field: {} {}", field, sensitiveSerializerConfig);
                    beanPropertyWriter.assignSerializer(new JacksonSensitiveSerializer(field, serializer));
                }
            }
        }
        return beanProperties;
    }

    /**
     * 是否是String
     */
    private boolean isStringType(BeanPropertyWriter writer) {
        Class<?> clazz = writer.getType().getRawClass();
        return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
    }
}
